package com.github.elliot.gatewaycenter.security.config;

import com.github.elliot.gatewaycenter.security.converter.JwtAuthenticationConverter;
import com.github.elliot.gatewaycenter.security.converter.RefreshTokenAuthenticationConverter;
import com.github.elliot.gatewaycenter.security.converter.UsernamePasswordAuthenticationConverter;
import com.github.elliot.gatewaycenter.security.filters.CustomAuthorizationWebFilter;
import com.github.elliot.gatewaycenter.security.filters.JwtAuthenticationFilter;
import com.github.elliot.gatewaycenter.security.filters.RefreshTokenAuthenticationFilter;
import com.github.elliot.gatewaycenter.security.filters.UsernamePasswordAuthenticationFilter;
import com.github.elliot.gatewaycenter.security.handlers.CustomServerAuthenticationFailureHandler;
import com.github.elliot.gatewaycenter.security.handlers.CustomServerAuthenticationSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.context.NoOpServerSecurityContextRepository;

@Configuration
@EnableWebFluxSecurity
public class ReactiveWebSecurityConfiguration {

    @Autowired
    private UsernamePasswordAuthenticationFilter.UsernamePasswordAuthenticationManager usernamePasswordAuthenticationManager;

    @Autowired
    private RefreshTokenAuthenticationFilter.RefreshTokenAuthenticationManager refreshTokenAuthenticationManager;

    @Autowired
    private CustomServerAuthenticationSuccessHandler customServerAuthenticationSuccessHandler;

    @Autowired
    private CustomServerAuthenticationFailureHandler customServerAuthenticationFailureHandler;

    @Autowired
    private UsernamePasswordAuthenticationConverter customAuthenticationConverter;

    @Autowired
    private JwtAuthenticationFilter.JwtAuthenticationManager jwtAuthenticationManager;

    @Autowired
    private JwtAuthenticationConverter jwtAuthenticationConverter;

    @Autowired
    private RefreshTokenAuthenticationConverter refreshTokenAuthenticationConverter;

    @Autowired
    private CustomAuthorizationWebFilter.PathBasedReactiveAuthorizationManager pathBasedReactiveAuthorizationManager;

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {

        UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter =
                new UsernamePasswordAuthenticationFilter(usernamePasswordAuthenticationManager,
                        customServerAuthenticationSuccessHandler,
                        customServerAuthenticationFailureHandler,
                        customAuthenticationConverter);

        RefreshTokenAuthenticationFilter refreshTokenAuthenticationFilter =
                new RefreshTokenAuthenticationFilter(refreshTokenAuthenticationManager,
                        customServerAuthenticationSuccessHandler,
                        customServerAuthenticationFailureHandler,
                        refreshTokenAuthenticationConverter);

        JwtAuthenticationFilter jwtAuthenticationFilter =
                new JwtAuthenticationFilter(jwtAuthenticationManager,
                        jwtAuthenticationConverter,
                        customServerAuthenticationFailureHandler);

        CustomAuthorizationWebFilter customAuthorizationWebFilter =
                new CustomAuthorizationWebFilter(pathBasedReactiveAuthorizationManager);

        http
                .csrf(ServerHttpSecurity.CsrfSpec::disable)
                .httpBasic(ServerHttpSecurity.HttpBasicSpec::disable)
                .formLogin(ServerHttpSecurity.FormLoginSpec::disable)
                .logout(ServerHttpSecurity.LogoutSpec::disable)
                .securityContextRepository(NoOpServerSecurityContextRepository.getInstance())
                .addFilterAt(usernamePasswordAuthenticationFilter, SecurityWebFiltersOrder.FORM_LOGIN)
                .addFilterAt(refreshTokenAuthenticationFilter, SecurityWebFiltersOrder.FORM_LOGIN)
                .addFilterAt(jwtAuthenticationFilter, SecurityWebFiltersOrder.AUTHENTICATION)
                .addFilterAt(customAuthorizationWebFilter, SecurityWebFiltersOrder.AUTHORIZATION);

        return http.build();
    }

}
